/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package crypbox.net.backend;

import crypbox.net.cryptograhy.Cryptograph;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URI;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import models.FilePart;
import models.Folder;
import models.MyFile;
import models.User;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.MultipartPostMethod;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 *
 * @author m-jay
 */
public class Backend {

    private static Backend instance = null;
    private String apiKey = "hierkommtderapikeyhin";
    private String authToken;
    private String ticket;
    private Einstellungen einstellungen;
    private String status = "";
    private User user;

    private Backend() {
        einstellungen = Einstellungen.getInstance();
    }

    public static Backend getInstance() {
        if (instance == null) {
            instance = new Backend();
        }
        return instance;
    }

    public boolean getTicket() {
        boolean success = false;
        try {

            SAXReader reader = new SAXReader();
            Document document = reader.read("https://www.box.net/api/1.0/rest?action=get_ticket&api_key=" + apiKey);


            Element root = document.getRootElement();

            // iterate through child elements of root
            for (Iterator i = root.elementIterator(); i.hasNext();) {
                Element element = (Element) i.next();

                if (element.getName().equals("status")) {
                    if (element.getText().equals("get_ticket_ok")) {
                        success = true;
                    }
                } else if (element.getName().equals("ticket")) {
                    ticket = element.getText();
                }

            }


        } catch (Exception ex) {
            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
        }

        return success;
    }

    public void authenticateUser() throws Exception {
        java.awt.Desktop desktop = java.awt.Desktop.getDesktop();
        desktop.browse(new URI("https://www.box.net/api/1.0/auth/" + ticket));
    }

    public boolean getAuthToken() {
        boolean success = false;

        try {

            SAXReader reader = new SAXReader();
            Document document = reader.read("https://www.box.net/api/1.0/rest?action=get_auth_token&api_key=" + apiKey + "&ticket=" + ticket);


            Element root = document.getRootElement();

            // iterate through child elements of root
            for (Iterator i = root.elementIterator(); i.hasNext();) {
                Element element = (Element) i.next();

                if (element.getName().equals("status")) {
                    if (element.getText().equals("get_auth_token_ok")) {
                        success = true;

                    }
                } else if (element.getName().equals("user")) {
                    Iterator nodeIterator = element.nodeIterator();

                    user = new User();

                    while (nodeIterator.hasNext()) {
                        Element next = (Element) nodeIterator.next();

                        if (next.getName().equals("login")) {
                            user.setLogin(next.getData().toString());
                        } else if (next.getName().equals("email")) {
                            user.setEmail(next.getData().toString());
                        } else if (next.getName().equals("access_id")) {
                            user.setAccess_id(Long.parseLong(next.getData().toString()));
                        } else if (next.getName().equals("user_id")) {
                            user.setUser_id(Long.parseLong(next.getData().toString()));
                        } else if (next.getName().equals("space_amount")) {
                            user.setSpace_amount(Long.parseLong(next.getData().toString()));
                        } else if (next.getName().equals("space_used")) {
                            user.setSpace_used(Long.parseLong(next.getData().toString()));
                        } else if (next.getName().equals("max_upload_size")) {
                            user.setMax_upload_size(Long.parseLong(next.getData().toString()));
                        }
                    }
                } else if (element.getName().equals("auth_token")) {
                    authToken = (String) element.getData();
                }
            }


        } catch (Exception ex) {
            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
        }
        authToken = "bl9p6l6f4jprmnt0fcmh1zr8msb28xx3";
        success = true;
        return success;
    }

    public void parseOnlineBox() throws DocumentException {


        SAXReader reader = new SAXReader();
        System.out.println("https://www.box.net/api/1.0/rest?action=get_account_tree&api_key=" + apiKey + "&auth_token=" + authToken + "&folder_id=0&params[]=nozip");
        Document document = reader.read("https://www.box.net/api/1.0/rest?action=get_account_tree&api_key=" + apiKey + "&auth_token=" + authToken + "&folder_id=0&params[]=nozip");

        Element root = document.getRootElement();
        Iterator rootIterator = root.elementIterator();

        Element next = (Element) rootIterator.next();
        if (next.getData().equals("listing_ok")) {
            Element tree = (Element) rootIterator.next();
            Iterator treeIterator = tree.nodeIterator();

            Element rootFolderElement = (Element) treeIterator.next();
            Iterator rootFolderIterator = rootFolderElement.nodeIterator();

            Folder rootFolder = new Folder();
            analysiereOnlineBox(rootFolder, rootFolderIterator);
            einstellungen.setOnlineBox(rootFolder);

        }
    }

    private List<Long> fileLocallyCreated(List<File> files, List<String> filenames, long parentID) {
        try {
            return upload(files, filenames, parentID);
        } catch (Exception ex) {
            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    private List<Long> fileLocallyUpdated(List<File> files, List<String> filenames, long parentID, MyFile oldMyFile, MyFile newFile) {
        try {

            if (oldMyFile.getDateiTeile().size() > newFile.getDateiTeile().size()) {

                for (int i = newFile.getDateiTeile().size(); i < oldMyFile.getDateiTeile().size(); i++) {
                    fileLocallyDeleted(oldMyFile.getDateiTeile().get(i).getId());
                }
            }

            return upload(files, filenames, parentID);
        } catch (Exception ex) {
            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    private void fileLocallyDeleted(long fileID) {
        deleteFile(fileID);
    }

    private void folderLocallyDeleted(long folderID) {
        deleteFolder(folderID);
    }

    private long folderLocallyAdded(long parentID, String foldername) {
        return createFolder(foldername, parentID);
    }

    private Folder parseLocalBox() {
        try {
            Folder cryptboxFolder = new Folder();
            cryptboxFolder.setName(einstellungen.getMyBox().getName());
            cryptboxFolder.setId(0);
            fillLocalFolderObject(einstellungen.getMyBox(), cryptboxFolder);
            return cryptboxFolder;
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public String getChecksum(byte[] bytes) {
        return DigestUtils.shaHex(bytes);
    }

    private void fillLocalFolderObject(File file, Folder folder) throws FileNotFoundException, IOException {
        if (!file.isHidden()) {
            if (file.isFile()) {
                MyFile myFile = new MyFile();
                myFile.setName(file.getName());

                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
                byte[] buffer = new byte[(int) einstellungen.getSplitgroesse()];
                int length;
                int i = 0;
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                do {
                    length = bis.read(buffer);

                    if (length != -1) {
                        try {
                            baos.reset();
                            baos.write(buffer, 0, length);
                            String checksum = getChecksum(Cryptograph.getInstance().encryptBytes(baos.toByteArray()));
                            myFile.getDateiTeile().put(i, new FilePart(checksum));
                        } catch (NoSuchAlgorithmException ex) {
                            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
                        } catch (InvalidKeyException ex) {
                            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
                        } catch (NoSuchPaddingException ex) {
                            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
                        } catch (IllegalBlockSizeException ex) {
                            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
                        } catch (BadPaddingException ex) {
                            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                    myFile.setUpdated(file.lastModified());
                    myFile.setSize(file.length());
                    folder.getFiles().put(file.getName(), myFile);
                    i++;
                } while (length != -1);
                baos.close();

            } else {


                if (!file.equals(einstellungen.getMyBox())) {
                    Folder subFolder = new Folder();
                    subFolder.setParent(folder);
                    subFolder.setName(file.getName());
                    folder.getFolders().put(file.getName(), subFolder);
                    folder = subFolder;
                }
                File[] listFiles = file.listFiles();
                for (File subsubfile : listFiles) {
                    fillLocalFolderObject(subsubfile, folder);
                }
            }
        }
    }

    private void clearTempfolder() {
        File[] listFiles = einstellungen.getTempfolder().listFiles();
        for (File f : listFiles) {
            deleteFolder(f);
        }
    }

    private void synchronisiere() throws Exception {

        clearTempfolder();

        long start = System.nanoTime();
        Folder newLocalbox = parseLocalBox();

        findLocalUpdates(einstellungen.getLocalBox(), newLocalbox, einstellungen.getMyBox().getAbsolutePath());

        einstellungen.setLocalBox(newLocalbox);


        parseOnlineBox();
        findOnlineUpdates(einstellungen.getLocalBox(), einstellungen.getOnlineBox(), einstellungen.getMyBox().getAbsolutePath());
        long stop = System.nanoTime();
        System.out.println("Dauer: " + (stop - start));


    }
    private transient GetMethod currentDownloadGetMethod = null;

    private InputStream downloadFile(long fileID) throws IOException {
        System.out.println("download");
        HttpClient client = new HttpClient();
        currentDownloadGetMethod = new GetMethod("https://www.box.net/api/1.0/download/" + authToken + "/" + fileID);
        client.executeMethod(currentDownloadGetMethod);
        return currentDownloadGetMethod.getResponseBodyAsStream();
    }

    private Folder findSubFolderByID(Folder folder, long folderid) {
        Iterator<String> iterator = folder.getFolders().keySet().iterator();
        while (iterator.hasNext()) {
            String folderName = iterator.next();
            Folder f = folder.getFolders().get(folderName);
            if (f.getId() == folderid) {
                return f;
            } else {
                f = findSubFolderByID(f, folderid);
                if (f != null) {
                    return f;
                }
            }
        }
        return null;
    }

    private void findOnlineUpdates(Folder localBox, Folder onlineBox, String path) throws Exception {
        Iterator<String> onlineFilesIterator = onlineBox.getFiles().keySet().iterator();

        if (localBox == null) {
            Folder localParentFolder = findSubFolderByID(localBox, onlineBox.getId());
            File localFolder = new File(path);
            localFolder.mkdirs();

            localBox = new Folder();
            localBox.setName(localFolder.getName());
            localBox.setParent(localParentFolder);
            localBox.setId(onlineBox.getId());
            localParentFolder.getFolders().put(localFolder.getName(), localBox);
        }


        while (onlineFilesIterator.hasNext()) {
            String fileName = onlineFilesIterator.next();
            File localFileHandle = new File(path + File.separator + fileName);
            MyFile onlineFile = onlineBox.getFiles().get(fileName);



            //Datei muss auf aktualität überprüft werden
            MyFile localFile = localBox.getFiles().get(fileName);

            boolean differenceFound = false;
            if (localFile == null) {
                differenceFound = true;
            }
            for (int i = 0; i < onlineFile.getDateiTeile().size() && !differenceFound; i++) {
                FilePart onlinePart = onlineFile.getDateiTeile().get(i);
                FilePart localPart = localFile.getDateiTeile().get(i);

                if (localPart == null) {
                } else {
                    localPart.setId(onlinePart.getId());
                    if (!onlinePart.getHash().equals(localPart.getHash())) {
                        differenceFound = true;
                    }
                }
            }
            if (differenceFound) {
                localFile = new MyFile();
                localBox.getFiles().put(fileName, localFile);
                localFileHandle.getParentFile().mkdirs();
                localFileHandle.delete();
                localFileHandle.createNewFile();

                FileOutputStream fos = new FileOutputStream(localFileHandle);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                for (int i = 0; i < onlineFile.getDateiTeile().size(); i++) {

                    baos.reset();
                    FilePart onlinePart = onlineFile.getDateiTeile().get(i);
                    InputStream downloadStream = downloadFile(onlinePart.getId());
                    FilePart localFilePart = new FilePart(onlinePart.getHash());
                    localFilePart.setId(onlinePart.getId());
                    localFile.getDateiTeile().put(i, localFilePart);

                    byte[] buffer = new byte[einstellungen.getSplitgroesse()];
                    int len = downloadStream.read(buffer);


                    while (len != -1) {
                        baos.write((buffer), 0, len);
                        len = downloadStream.read(buffer);
                    }
                    downloadStream.close();
                    if (currentDownloadGetMethod != null) {
                        currentDownloadGetMethod.releaseConnection();
                        currentDownloadGetMethod = null;
                    }
                    fos.write(Cryptograph.getInstance().decryptBytes(baos.toByteArray()));
                }
                baos.close();
                fos.close();


            }
        }
        Iterator<String> localFilesIterator = localBox.getFiles().keySet().iterator();
        while (localFilesIterator.hasNext()) {
            String fileName = localFilesIterator.next();
            if (!onlineBox.getFiles().containsKey(fileName)) {
                File f = new File(path + File.separator + fileName);
                f.delete();
                localFilesIterator.remove();
            }
        }


        Iterator<String> onlineFoldersIterator = onlineBox.getFolders().keySet().iterator();
        while (onlineFoldersIterator.hasNext()) {
            String folderName = onlineFoldersIterator.next();
            Folder localFolder = localBox.getFolders().get(folderName);
            Folder onlineFolder = onlineBox.getFolders().get(folderName);

            if (localFolder == null) {

                localFolder = new Folder();
                localFolder.setParent(localBox);
                localFolder.setName(onlineFolder.getName());
                localBox.getFolders().put(folderName, localFolder);
                File localFolderHandle = new File(path + File.separator + onlineFolder.getName());
                localFolderHandle.mkdirs();
            }
            localFolder.setId(onlineFolder.getId());
            findOnlineUpdates(localFolder, onlineFolder, path + File.separator + onlineFolder.getName());
        }

        Iterator<String> localFoldersIterator = localBox.getFolders().keySet().iterator();

        while (localFoldersIterator.hasNext()) {
            String folderName = localFoldersIterator.next();
            if (!onlineBox.getFolders().containsKey(folderName)) {
                File deletableFolder = new File(path + File.separator + folderName);
                deleteFolder(deletableFolder);
                localFoldersIterator.remove();
            }
        }
    }

    private void deleteFolder(File folder) {
        if (folder.isDirectory()) {
            File[] listFiles = folder.listFiles();
            for (File f : listFiles) {
                deleteFolder(f);
            }
            folder.delete();
        } else {
            folder.delete();
        }
    }

    private void findLocalUpdates(Folder oldfolder, Folder newFolder, String folderpath) throws Exception {
        Iterator<String> newFilesIterator = newFolder.getFiles().keySet().iterator();
        while (newFilesIterator.hasNext()) {
            String fileName = newFilesIterator.next();
            MyFile newFile = newFolder.getFiles().get(fileName);
            if (oldfolder != null) {
                if (oldfolder.getFiles().get(fileName) != null) {
                    MyFile oldFile = oldfolder.getFiles().get(fileName);
                    //Die neue Datei kann nun nur neuer sein
                    List<File> files = new ArrayList<File>();
                    List<String> filenames = new ArrayList<String>();
                    boolean differenceFound = false;
                    List<Integer> fileNumbers = new ArrayList<Integer>();
                    for (int i = 0; i < newFile.getDateiTeile().size(); i++) {
                        if (!watchStarted) {
                            FilePart newPart = newFile.getDateiTeile().get(i);
                            FilePart oldPart = oldFile.getDateiTeile().get(i);
                            if (oldPart == null || !oldPart.getHash().equals(newPart.getHash())) {

                                FileInputStream fis = new FileInputStream(new File(folderpath + File.separator + fileName));
                                fis.skip(einstellungen.getSplitgroesse() * i);
                                byte[] buffer = new byte[(int) einstellungen.getSplitgroesse()];
                                int length = fis.read(buffer);
                                File temp = File.createTempFile(fileName, "_" + i);
                                FileOutputStream fos = new FileOutputStream(temp);
                                fos.write(buffer, 0, length);
                                fis.close();
                                fos.close();
                                files.add(temp);
                                filenames.add(fileName + "_" + i);
                                fileNumbers.add(i);
                                differenceFound = true;
                            }
                        }
                    }
                    if (watchStarted && newFile.getDateiTeile().size() != oldFile.getDateiTeile().size()) {
                        differenceFound = true;
                    }
                    if (watchStarted && differenceFound) {
                        List<Long> partIDs = fileLocallyUpdated(files, filenames, newFolder.getId(), oldFile, newFile);
                        for (int i = 0; i < fileNumbers.size(); i++) {
                            newFile.getDateiTeile().get(fileNumbers.get(i)).setId(partIDs.get(i));
                        }
                    }
                } else {
                    FileInputStream fis = new FileInputStream(new File(folderpath + File.separator + fileName));
                    List<File> files = new ArrayList<File>();
                    List<String> filenames = new ArrayList<String>();
//                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    for (int i = 0; i < newFile.getDateiTeile().size(); i++) {
                        if (watchStarted) {
//                        baos.reset();
                            byte[] buffer = new byte[(int) einstellungen.getSplitgroesse()];
                            int length = fis.read(buffer);
                            File temp = File.createTempFile(fileName, "_" + i);
                            FileOutputStream fos = new FileOutputStream(temp);
                            fos.write(buffer, 0, length);
//                        fos.write(Cryptograph.getInstance().encryptBytes(baos.toByteArray()));
                            files.add(temp);
                            filenames.add(fileName + "_" + i);
                        }
                    }
//                    baos.close();
                    fis.close();
                    if (watchStarted) {
                        List<Long> partIDs = fileLocallyCreated(files, filenames, newFolder.getId());
                        for (int i = 0; i < newFile.getDateiTeile().size(); i++) {
                            newFile.getDateiTeile().get(i).setId(partIDs.get(i));
                        }
                    }
                }
                oldfolder.getFiles().remove(fileName);
            } else {
                //Die neue Datei befindet sich in einem neuen Ordner und muss daher hochgeladen werden
                FileInputStream fis = new FileInputStream(new File(folderpath + File.separator + fileName));
                List<File> files = new ArrayList<File>();
                List<String> filenames = new ArrayList<String>();
                for (int i = 0; i < newFile.getDateiTeile().size(); i++) {
                    byte[] buffer = new byte[(int) einstellungen.getSplitgroesse()];
                    int length = fis.read(buffer);
                    File temp = File.createTempFile(fileName, "_" + i);
                    FileOutputStream fos = new FileOutputStream(temp);
                    fos.write(buffer, 0, length);
                    fos.close();
                    files.add(temp);
                    filenames.add(fileName + "_" + i);
                }
                fis.close();
                List<Long> partIDs = fileLocallyCreated(files, filenames, newFolder.getId());
                for (int i = 0; i < newFile.getDateiTeile().size(); i++) {
                    newFile.getDateiTeile().get(i).setId(partIDs.get(i));
                }

            }
        }
        if (oldfolder != null && watchStarted) {
            Iterator<String> oldFilesIterator = oldfolder.getFiles().keySet().iterator();
            while (watchStarted && oldFilesIterator.hasNext()) {
                String fileName = oldFilesIterator.next();
                MyFile oldfile = oldfolder.getFiles().get(fileName);

                for (int i = 0; i < oldfile.getDateiTeile().size(); i++) {
                    FilePart part = oldfile.getDateiTeile().get(i);
                    long id = part.getId();
                    fileLocallyDeleted(id);
                }
            }
        }
        Iterator<String> newFolderIterator = newFolder.getFolders().keySet().iterator();
        while (watchStarted && newFolderIterator.hasNext()) {

            Folder oldSub = null;
            String folderName = newFolderIterator.next();
            if (oldfolder != null && oldfolder.getFolders().get(folderName) != null) {

                oldSub = oldfolder.getFolders().get(folderName);
                newFolder.getFolders().get(folderName).setId(oldSub.getId());
                oldfolder.getFolders().remove(folderName);
            } else {

                long folderID = folderLocallyAdded(newFolder.getId(), folderName);
                newFolder.getFolders().get(folderName).setId(folderID);
            }
            findLocalUpdates(oldSub, newFolder.getFolders().get(folderName), folderpath + File.separator + folderName);
        }
        if (oldfolder != null) {
            Iterator<String> oldFolderIterator = oldfolder.getFolders().keySet().iterator();
            while (oldFolderIterator.hasNext()) {
                String folderName = oldFolderIterator.next();
                Folder folder = oldfolder.getFolders().get(folderName);
                folderLocallyDeleted(folder.getId());
            }
        }
    }

    private void analysiereOnlineBox(Folder folder, Iterator nodeIterator) {

        while (nodeIterator.hasNext()) {
            Element next = (Element) nodeIterator.next();
            if (next.getName().equals("folders")) {
                Iterator foldersIterator = next.nodeIterator();

                while (foldersIterator.hasNext()) {
                    Element subFolderElement = (Element) foldersIterator.next();
                    Attribute attribute = subFolderElement.attribute("name");
                    long id = Long.parseLong(subFolderElement.attributeValue("id"));

                    String foldername = Util.demaskiereUmlaute(attribute.getData().toString());
                    Folder subFolder = folder.getFolders().get(foldername);
                    if (subFolder == null) {
                        subFolder = new Folder();
                        subFolder.setParent(folder);
                        subFolder.setName(foldername);
                        subFolder.setId(id);
                        folder.getFolders().put(subFolder.getName(), subFolder);
                    }

                    analysiereOnlineBox(subFolder, subFolderElement.nodeIterator());
                }
            } else if (next.getName().equals(("files"))) {
                Iterator filesIterator = next.nodeIterator();
                while (filesIterator.hasNext()) {
                    Element file = (Element) filesIterator.next();
                    String uploadedName = file.attributeValue("file_name");
                    String sha1 = file.attributeValue("sha1");
                    Long updated = Long.parseLong(file.attributeValue("updated"));
                    Long size = Long.parseLong(file.attributeValue("size"));
                    Long id = Long.parseLong(file.attributeValue("id"));

                    String[] split = uploadedName.split("_");

                    String name = split[0];
                    for (int i = 1; i < split.length - 1; i++) {
                        name += "_" + split[i];
                    }

                    name = Util.demaskiereUmlaute(name);

                    String nummer = split[split.length - 1];
                    int nummerInt = Integer.parseInt(nummer);
                    MyFile myFile = folder.getFiles().get(name);

                    if (myFile == null) {
                        myFile = new MyFile();
                        folder.getFiles().put(name, myFile);
                    }
                    FilePart filePart = new FilePart(sha1);
                    filePart.setId(id);
                    myFile.getDateiTeile().put(nummerInt, filePart);

                    if (myFile.getUpdated() < updated) {
                        myFile.setUpdated(updated);
                    }
                    myFile.setSize(myFile.getSize() + size);

                }
            }
        }
    }

    private List<Long> upload(List<File> files, List<String> filenames, long parentID) throws Exception {
        List<Long> idList = new ArrayList<Long>(files.size());
        try {
            HttpClient client = new HttpClient();

            MultipartPostMethod multi = new MultipartPostMethod("https://upload.box.net/api/1.0/upload/" + authToken + "/" + parentID);
            multi.getParams().setContentCharset("utf-8");
            multi.setRequestHeader("ContentType", "application/x-www-form-urlencoded;charset=UTF-8");
            for (int j = 0; j < files.size(); j++) {
                File f = files.get(j);
                String filename = filenames.get(j);
                filename = Util.maskiereUmlaute(filename);

                if (f.isFile()) {



                    einstellungen.getTempfolder().mkdirs();
                    File encryptedFile = new File(einstellungen.getTempfolder(), filename);
                    encryptedFile.delete();
                    encryptedFile.createNewFile();

                    Cryptograph.getInstance().encryptFile(f, encryptedFile);
                    multi.addParameter(filename, encryptedFile);
                }

                if (j % 18 == 0 || j == files.size() - 1) {
                    client.executeMethod(multi);
                    SAXReader reader = new SAXReader();
                    Document document = reader.read(multi.getResponseBodyAsStream());
                    multi.releaseConnection();

                    Iterator docIterator = document.nodeIterator();
                    while (docIterator.hasNext()) {
                        Element next = (Element) docIterator.next();
                        if (next.getName().equals("response")) {
                            Iterator responseIterator = next.nodeIterator();
                            while (responseIterator.hasNext()) {
                                Element subResponse = (Element) responseIterator.next();
                                if (subResponse.getName().equals("files")) {
                                    Iterator filesIterator = subResponse.nodeIterator();
                                    while (filesIterator.hasNext()) {
                                        Element file = (Element) filesIterator.next();
                                        long fileID = Long.parseLong(file.attribute("id").getValue());
                                        idList.add(fileID);
                                    }
                                }
                            }
                        }
                    }
                    multi = new MultipartPostMethod("https://upload.box.net/api/1.0/upload/" + authToken + "/" + parentID);
                    multi.getParams().setContentCharset("utf-8");
                    multi.setRequestHeader("ContentType", "application/x-www-form-urlencoded;charset=UTF-8");

                }

            }


        } catch (IOException ex) {
            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
        }
        return idList;
    }

    public long createFolder(String ordnername, long parentID) {
        long ordnerID = -99;


        SAXReader reader = new SAXReader();
        try {
            ordnername = Util.maskiereUmlaute(ordnername);
            if (!ordnername.equals("")) {
                System.out.println("https://www.box.net/api/1.0/rest?action=create_folder&api_key=" + apiKey + "&auth_token=" + authToken + "&parent_id=" + parentID + "&name=" + ordnername + "&share=0");
                Document document = reader.read("https://www.box.net/api/1.0/rest?action=create_folder&api_key=" + apiKey + "&auth_token=" + authToken + "&parent_id=" + parentID + "&name=" + ordnername + "&share=0");
                Element root = document.getRootElement();
                Iterator rootIterator = root.elementIterator();
                if (rootIterator.hasNext()) {
                    Element next = (Element) rootIterator.next();
                    if (!next.getData().equals("create_ok") && !next.getData().equals("s_folder_exists")) {
                        throw new Exception("Fehler beim Ordneranlegen: Angelegt werden sollte der Ordner: '" + ordnername + "'\nMeldung: " + next.getData().toString());
                    }
                } else {
                    throw new Exception("Fehler bei der Ordnerübertragung");
                }
                if (rootIterator.hasNext()) {
                    Element next = (Element) rootIterator.next();
                    Iterator nodeIterator = next.nodeIterator();
                    while (nodeIterator.hasNext()) {
                        {
                            Element folderEintrag = (Element) nodeIterator.next();
                            if (folderEintrag.getName().equals("folder_id")) {
                                ordnerID = Long.parseLong((String) folderEintrag.getData());
                            }
                        }
                    }
                }
            }
        } catch (Exception ex) {
            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
        }
        return ordnerID;
    }

    private void deleteFile(long fileID) {
        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read("https://www.box.net/api/1.0/rest?action=delete&api_key=" + apiKey + "&auth_token=" + authToken + "&target=file&target_id=" + fileID);

        } catch (DocumentException ex) {
            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void deleteFolder(long folderID) {
        try {
//            SAXReader reader = new SAXReader();
//            Document document = reader.read("https://www.box.net/api/1.0/rest?action=delete&api_key=" + apiKey + "&auth_token=" + authToken + "=folder&target_id=" + folderID);

            HttpClient client = new HttpClient();
            GetMethod gm = new GetMethod("https://www.box.net/api/1.0/rest?action=delete&api_key=" + apiKey + "&auth_token=" + authToken + "&target=folder&target_id=" + folderID);
            client.executeMethod(gm);
//            System.out.println(gm.getResponseBodyAsString
            gm.releaseConnection();

        } catch (IOException ex) {
            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    private transient boolean watchStarted = false;
    private Thread watchThread = null;

    public synchronized void startWatching() {

        if (!watchStarted) {
            watchStarted = true;

            watchThread = new Thread() {

                @Override
                public void run() {
                    while (watchStarted) {
                        try {
                            if (getTicket()) {
                                Backend.getInstance().getAuthToken();
                                synchronisiere();
                            }
                            Thread.sleep(5 * 60 * 1000);
                        } catch (Exception ex) {
                            Logger.getLogger(Backend.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }

                }

                @Override
                public void interrupt() {





                    super.interrupt();

                }
            };
            watchThread.start();
        }
    }

    public void stopWatching() {

        if (watchThread != null) {
            watchThread.interrupt();
            watchThread = null;
        }
        watchStarted = false;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }
}
